﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Migracion.Data;
using Migracion.Data.PeOnline;
using System.Diagnostics;
using System.Xml.Linq;
using System.IO;
using Migracion.Data.Tagging;
using System.Text.RegularExpressions;
using System.Web;
using Migracion.Process.voz;
using Migracion.Data.ArbolVoces;
using System.Data.SqlClient;
using System.Data.Common;
using System.Configuration;

namespace Migracion.Process
{
    public class DoctrinaProc : BaseProcess
    {
        public const string StrEstadoConTexto = "Con texto";
        public const string StrEstadoSinTexto = "Sin texto";
        public const string StrNotaInterna = "ORIGEN_ABELEDO_PERROT";
        public const string StrPais = "Argentina AP";

        public int IdCuerpoParam { get; set; }

        public bool ProcesarSoloIdCuerpo { get; set; }

        public bool ProcesarSoloIndice { get; set; }

        public string OutputPath { get; set; }

        public bool ProcesarDoctrina { get; set; }

        public string AbeledoId { get; set; }

        public string SQLText { get; set; }

        private bool cancelaProceso = false;
        private object cancelaProcesoLock = false;

        public bool CancelarProceso
        {
            get
            {
                lock (cancelaProcesoLock)
                {
                    return cancelaProceso;
                }
            }
            set
            {
                lock (cancelaProcesoLock)
                {
                    cancelaProceso = value;
                }
            }
        }

        public void DoProcess()
        {
            if (ProcesarDoctrina)
            {
                DoProcessDoctrina();
            }
            else
            {
                DoProcessObras();
            }
        }


        protected void DoProcessDoctrina()
        {
            int imax = 0;
            try
            {
                watch.Start();
                LogStatusMessage("Inicio de Generación de XMLs de Doctrina", MigracionLogStatus.Information); // Actualizado para Doctrina
                InicializarManagers();

                List<int> Ids = new List<int>();
                using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
                {
                    // Leer los datos
                    Ids = ObtenerIdsAProcesarDoctrina(ctxPeOnline);

                    if (Ids.Count == 0)
                    {
                        LogStatusMessage("No se encontraron doctrinas para procesar", MigracionLogStatus.Information);
                    }
                }

                // Por cada dato,
                imax = Ids.Count;
                bool cancelar = false;
                for (int i = 0; i < imax && !cancelar; i++)
                {
                    int idFallo = Ids[i];
                    currentId = idFallo.ToString();
                    if (CancelarProceso)
                    {
                        cancelar = true;
                    }
                    else
                    {

                        if (i % 5000 == 0)
                        {
                            GC.Collect();
                        }

                        // generar el XML
                        try
                        {
                            GenerarXMLDoctrina(idFallo);
                            cantidadDeFallosOk++;
                            LogStatusMessage("Doctrina procesada: " + idFallo.ToString(), MigracionLogStatus.Information);
                        }
                        catch (Exception exIndividual)
                        {
                            LogStatusMessage("Error excepción en el documento " + GetExceptionMessage(exIndividual) + GetExceptionStackTrace(exIndividual), MigracionLogStatus.Error);
                        }

                        ProgressStatus(i + 1, imax);
                    }
                }
            }
            catch (Exception ex)
            {
                LogStatusMessage("Ha ocurrido una excepción: " + GetExceptionMessage(ex) + GetExceptionStackTrace(ex), MigracionLogStatus.Error);
            }
            finally
            {
                if (CancelarProceso)
                {
                    LogStatusMessage("Proceso Cancelado", MigracionLogStatus.Information);
                }
                else
                {
                    LogStatusMessage(string.Format("Proceso Finalizado, procesados ok {0} de {1}", cantidadDeFallosOk, imax), MigracionLogStatus.Information);
                }

                watch.Stop();
            }
        }

        protected void DoProcessObras()
        {
            int imax = 0;
            try
            {
                watch.Start();
                LogStatusMessage("Inicio de Generación de XMLs de Obras", MigracionLogStatus.Information); // Actualizado para Obras
                InicializarManagers();

                List<int> Ids = new List<int>();
                using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
                {
                    // Leer los datos
                    Ids = ObtenerIdsAProcesarObras(ctxPeOnline);

                    if (Ids.Count == 0)
                    {
                        LogStatusMessage("No se encontraron obras para procesar", MigracionLogStatus.Information);
                    }
                }

                // Por cada dato,
                imax = Ids.Count;
                bool cancelar = false;
                for (int i = 0; i < imax && !cancelar; i++)
                {
                    int idObra = Ids[i];
                    currentId = idObra.ToString();
                    if (CancelarProceso)
                    {
                        cancelar = true;
                    }
                    else
                    {
                        if (i % 5000 == 0)
                        {
                            GC.Collect();
                        }
                        // generar el XML
                        try
                        {
                            GenerarXMLObra(idObra);
                            cantidadDeFallosOk++;
                            LogStatusMessage("Obra Procesada: " + idObra.ToString(), MigracionLogStatus.Information);
                        }
                        catch (Exception exIndividual)
                        {
                            LogStatusMessage("Error excepción en el documento " + GetExceptionMessage(exIndividual) + GetExceptionStackTrace(exIndividual), MigracionLogStatus.Error);
                        }

                        ProgressStatus(i + 1, imax);
                    }
                }
            }
            catch (Exception ex)
            {
                LogStatusMessage("Ha ocurrido una excepción: " + GetExceptionMessage(ex) + GetExceptionStackTrace(ex), MigracionLogStatus.Error);
            }
            finally
            {
                if (CancelarProceso)
                {
                    LogStatusMessage("Proceso Cancelado", MigracionLogStatus.Information);
                }
                else
                {
                    LogStatusMessage(string.Format("Proceso Finalizado, procesados ok {0} de {1}", cantidadDeFallosOk, imax), MigracionLogStatus.Information);
                }

                watch.Stop();
            }
        }

        private List<int> ObtenerIdsAProcesarDoctrina(PE_ONLINE_PRODUCCIONEntities ctxPeOnline)
        {
            List<int> ids = new List<int>();
            if (!String.IsNullOrEmpty(SQLText))
            {
                string constr = ConfigurationManager.ConnectionStrings["PE_ONLINE_PRODUCCIONSelect"].ConnectionString;
                using (DbConnection connection = new SqlConnection(constr))
                {
                    try
                    {
                        connection.Open();
                        DbCommand command = connection.CreateCommand();
                        command.CommandText = this.SQLText;
                        command.CommandType = System.Data.CommandType.Text;

                        using (DbDataReader reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                ids.Add(reader.GetInt32(0));
                            }

                            reader.Close();
                        }
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
            else // Actualice este codigo para Doctrina
            {
                if (!String.IsNullOrEmpty(AbeledoId))
                {
                    int? idDoctrina = (from ds in ctxPeOnline.tDoctrinaSumario
                                       join il in ctxPeOnline.tIdentLexis on ds.IdIdentLexis equals il.Id
                                       where il.IdentLexis == AbeledoId
                                       && ds.IdIdentLexis.HasValue
                                       select ds.IdDDSumario).SingleOrDefault();

                    if (idDoctrina.HasValue && idDoctrina.Value != default(int))
                    {
                        ids.Add(idDoctrina.Value);
                    }
                }
                else
                {
                    ids.AddRange((from ds in ctxPeOnline.tDoctrinaSumario
                                  join il in ctxPeOnline.tIdentLexis on ds.IdIdentLexis equals il.Id
                                  where ds.IdIdentLexis.HasValue
                                  select ds.IdDDSumario).ToList());
                }
            }

            return ids;
        }

        private List<int> ObtenerIdsAProcesarObras(PE_ONLINE_PRODUCCIONEntities ctxPeOnline)
        {
            List<int> ids = new List<int>();
            if (!String.IsNullOrEmpty(SQLText))
            {
                string constr = ConfigurationManager.ConnectionStrings["PE_ONLINE_PRODUCCIONSelect"].ConnectionString;
                using (DbConnection connection = new SqlConnection(constr))
                {
                    try
                    {
                        connection.Open();
                        DbCommand command = connection.CreateCommand();
                        command.CommandText = this.SQLText;
                        command.CommandType = System.Data.CommandType.Text;

                        using (DbDataReader reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                ids.Add(reader.GetInt32(0));
                            }

                            reader.Close();
                        }
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
            //else // Actualice este codigo para Obras
            //{
            //    if (!String.IsNullOrEmpty(AbeledoId))
            //    {
            //        int? idObra = (from oc in ctxPeOnline.tObraCuerpo
            //                           join il in ctxPeOnline.tIdentLexis on oc.IdIdentLexis equals il.Id
            //                           where il.IdentLexis == AbeledoId
            //                           && oc.IdIdentLexis.HasValue
            //                           select oc.IdObraD).SingleOrDefault();

            //        if (idObra.HasValue && idObra.Value != default(int))
            //        {
            //            ids.Add(idObra.Value);
            //        }
            //    }
            //    else
            //    {
            //        ids.AddRange((from oc in ctxPeOnline.tObraCuerpo
            //                      join il in ctxPeOnline.tIdentLexis on oc.IdIdentLexis equals il.Id
            //                      where oc.IdIdentLexis.HasValue
            //                      select oc.IdObra).ToList());
            //    }
            //}

            return ids;
        }

        private void GenerarXMLDoctrina(int idDoctrina)
        {
            string nombreDocumento = idDoctrina.ToString() + ".xml";
            MigraDocLog migraDocLogEntry = new MigraDocLog();
            migraDocLogEntry.NombreArchivoGenerado = nombreDocumento;
            migraDocLogEntry.ApNombreTabla = IdentityTranslationManager.tDoctrinaSumario;
            migraDocLogEntry.Excepcion = false;
            migraDocLogEntry.Mensaje = string.Empty;

            using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
            {
                try
                {
                    XDocument doctrinaDocument = new XDocument();

                    tDoctrinaSumario tDoctrinaSumario = ctxPeOnline.tDoctrinaSumario.Where(f => f.IdDDSumario == idDoctrina).SingleOrDefault();

                    if (tDoctrinaSumario == null)
                    {
                        LogStatusMessage("No se encontró la doctrina", MigracionLogStatus.Information);
                        return;
                    }

                    // Analizo si la doctrina pertenece a un grupo
                    MigraDoctrinaGrupo grupoDoctrina = (from gs in ctxPeOnline.MigraDoctrinaGrupo
                                               join gsd in ctxPeOnline.MigraDoctrinaGrupoDetalle on gs.Id equals gsd.MigraDoctrinaGrupoId
                                               where gsd.IdDDSumario == idDoctrina
                                               select gs).FirstOrDefault();

                    bool procesar = true;
                    
                    List<tDoctrinaSumario> doctrinaSumarioList = new List<tDoctrinaSumario>();
                    if (grupoDoctrina == null)
                    {
                        // Analizo si hay que crear un grupo
                        doctrinaSumarioList = ctxPeOnline.tDoctrinaSumario.Where(f => f.IdDDTexto == tDoctrinaSumario.IdDDTexto && f.IdIdentLexis.HasValue).ToList();
                        // Creo un grupo
                        if (doctrinaSumarioList.Count > 0)
                        {
                            grupoDoctrina = new MigraDoctrinaGrupo();
                            ctxPeOnline.MigraDoctrinaGrupo.AddObject(grupoDoctrina);
                            grupoDoctrina.Procesado = false;
                            grupoDoctrina.IdDDTexto = tDoctrinaSumario.IdDDTexto;

                            foreach (tDoctrinaSumario dsval in doctrinaSumarioList)
                            {
                                MigraDoctrinaGrupoDetalle doctrinaDetalle = new MigraDoctrinaGrupoDetalle();
                                doctrinaDetalle.IdDDSumario = dsval.IdDDSumario;
                                grupoDoctrina.MigraDoctrinaGrupoDetalle.Add(doctrinaDetalle);
                            }

                            ctxPeOnline.SaveChanges();
                        }
                        else
                        {
                            // Agrego la actual
                            doctrinaSumarioList.Add(tDoctrinaSumario);
                        }
                    }
                    else
                    {
                        // Cargo el grupo si no se proceso
                        if (!grupoDoctrina.Procesado)
                        {
                            foreach (var detalle in grupoDoctrina.MigraDoctrinaGrupoDetalle)
                            {
                                doctrinaSumarioList.Add(ctxPeOnline.tDoctrinaSumario.Where(i => i.IdDDSumario == detalle.IdDDSumario && i.IdIdentLexis.HasValue).Single());
                            }
                        }
                        else
                        {
                            procesar = false;
                        }
                    }

                    if (procesar)
                    {
                        XElement documentoElement = new XElement("documento");
                        doctrinaDocument.Add(documentoElement);
                        XElement metaDocumentoElement = new XElement("meta-documento");
                        documentoElement.Add(metaDocumentoElement);

                        // 21-08-11 Agregado para documento de Doctrina
                        // 22-08-11 Se agregaron los valores
                        XElement tipoDoctrinaElement = new XElement("tipo-doctrina");
                        metaDocumentoElement.Add(tipoDoctrinaElement);
                        XElement subtipoDoctrinaElement = new XElement("subtipo-doctrina");
                        metaDocumentoElement.Add(subtipoDoctrinaElement);
                        if (tDoctrinaSumario.IdTipoDoc.HasValue)
                        {
                            tipoDoctrinaElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTipoDoc, tDoctrinaSumario.IdTipoDoc.Value); // 	La conversión que se haga de la tabla tTipoDoc (tDoctrinaSumario.IdTipoDoc) Igualmente en este caso la correspondencia será a un descripción. Es decir, en la tabla de conversión deberías tener para un id de la tabla tTipoDoc, una descripcion (VARCHAR) Tipo Doctrina de SAE y otra descripción VARCHAR, para el subtipo-doctrina también.
                            subtipoDoctrinaElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTipoDoc, tDoctrinaSumario.IdTipoDoc.Value);
                        }

                        XElement obraElement = new XElement("guid-obra");
                        metaDocumentoElement.Add(obraElement);
                        XElement doctrinaGuidElement = new XElement("guid");
                        metaDocumentoElement.Add(doctrinaGuidElement);
                        Guid doctrinaGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tDoctrinaSumario, idDoctrina);
                        doctrinaGuidElement.Value = doctrinaGuid.ToString();
                        migraDocLogEntry.ApId = idDoctrina.ToString();
                        migraDocLogEntry.GuidSae = doctrinaGuid;
                        metaDocumentoElement.Add(new XElement("iddoc")); // No informar
                        XElement citaElement = new XElement("cita");
                        metaDocumentoElement.Add(citaElement);

                        // Hay que poner el valor de todas las citas
                        StringBuilder citaBuilder = new StringBuilder();
                        string separador = string.Empty;
                        foreach (tDoctrinaSumario ds in doctrinaSumarioList)
                        {
                            citaBuilder.Append(separador);
                            separador = "~";
                            citaBuilder.Append(ds.tIdentLexis.IdentLexis);
                        }

                        citaElement.Value = citaBuilder.ToString();

                        //citaElement.Value = tDoctrinaSumario.tIdentLexis.IdentLexis;
                        XElement novusElement = new XElement("novus", new XElement("id"), new XElement("accion", IdTranslationManager.GetDocumentoEstadoEnviarNovus(tDoctrinaSumario.IdDocumentoEstado)), new XElement("fecha-de-modificacion", "T"));
                        metaDocumentoElement.Add(novusElement);
                        XElement fechaDeCarga = new XElement("fecha-carga");
                        metaDocumentoElement.Add(fechaDeCarga);
                        fechaDeCarga.Value = tDoctrinaSumario.FechaAlta.ToStringSAE();
                        metaDocumentoElement.Add(new XElement("fecha-ultima-modificacion", DateTime.Now.ToStringSAE()));
                        metaDocumentoElement.Add(new XElement("estado-texto", StrEstadoConTexto));
                        metaDocumentoElement.Add(new XElement("notas-internas", StrNotaInterna)); // Cambio nota-interna por notas-internas

                        // 21-08-11 Modificado: Antes era titulo, ahora es titulo-publicado
                        // 22-08-11 Agregado el valor
                        XElement tituloElement = new XElement("titulo-publicado");
                        metaDocumentoElement.Add(tituloElement);
                        if (tDoctrinaSumario.Sumario != null)
                        {
                            tituloElement.Value = HtmlDecode(tDoctrinaSumario.Sumario);
                        }

                        // 21-08-11 Agrego materia
                        // 22-08-11 Averiguar el valor de las materias ya que incluye información sobre los GUID
                        XElement materiasElement = new XElement("materias");
                        metaDocumentoElement.Add(materiasElement);

                        List<int> materiasDeDoctrinaIdList = ctxPeOnline.tDoctrinaMateria.Where(dm => dm.IdDDSumario == tDoctrinaSumario.IdDDSumario).Select(dm => dm.id_Materia).ToList();
                        List<tMateria> materiasDeDoctrinaList = ctxPeOnline.tMateria.Where(dm => materiasDeDoctrinaIdList.Contains(dm.id_Materia)).ToList();
                        foreach (var tdoctrinaMateria in materiasDeDoctrinaList)
                        {
                            tMateria materia = ctxPeOnline.tMateria.Where(m => m.id_Materia == tdoctrinaMateria.id_Materia).Single();
                            List<Guid> guidSaeMateriaList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tMateria, materia.id_Materia);//GetGuidListIdForApEntity
                            foreach (Guid guidSaeMateria in guidSaeMateriaList)
                            {
                                XElement materiaElement = new XElement("materia");
                                materiaElement.Add(new XAttribute("identificador", materia.Identificador));
                                materiaElement.Add(new XAttribute("nombre", HtmlDecode(materia.Descripcion)));
                                materiaElement.Value = guidSaeMateria.ToString();
                                materiasElement.Add(materiaElement);
                            }
                        }

                        XElement aparicionesElement = new XElement("apariciones");
                        metaDocumentoElement.Add(aparicionesElement);

                        foreach (var doctrinacita in tDoctrinaSumario.tCita)
                        {
                            List<string> publicaciones = doctrinacita.Nombre.Split(';').ToList();
                            foreach (string publi in publicaciones)
                            {
                                string publicacion = publi.Trim();

                                CitaAp citaAp;
                                if (publicacion.StartsWith("RDAmb"))
                                {
                                    citaAp = JurisprudenciaProc.citasAP.Where(c => "RDAmb" == c.Starts).SingleOrDefault();
                                }
                                else if (publicacion.StartsWith("RDA"))
                                {
                                    citaAp = JurisprudenciaProc.citasAP.Where(c => "RDA" == c.Starts).SingleOrDefault();
                                }
                                else
                                {
                                    citaAp = JurisprudenciaProc.citasAP.Where(c => publicacion.StartsWith(c.Starts) && c.TipoDeCita == CitaAp.aparicion).SingleOrDefault();
                                }                                

                                if (citaAp != null)
                                {
                                    //string productoPublicacion = publicacion.Substring(0, publicacion.IndexOf(' '));
                                    XElement aparicionElement = new XElement("aparicion");
                                    aparicionesElement.Add(aparicionElement);
                                    aparicionElement.Add(new XElement("coleccion", this.IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tPublicacionFallo, citaAp.Starts)));
                                    aparicionElement.Add(new XElement("componente")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("pag")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("fecha")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("nro-fallo")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("desc", HtmlDecode(publicacion))); // TODO: completar, ver
                                }
                            }
                        }

                        XElement citasElement = new XElement("citas");
                        JurisprudenciaProc.AgregarAnalisisDeCita(citasElement, tDoctrinaSumario.tCita);

                        metaDocumentoElement.Add(new XElement("pais", StrPais));

                        // No informar
                        metaDocumentoElement.Add(new XElement("aparicionesfuturas"));
                        metaDocumentoElement.Add(new XElement("boletin"));

                        // Agrego la parte de dato bibliografico para Doctrina
                        XElement datobibliograficoElement = new XElement("dato-bibliografico");
                        metaDocumentoElement.Add(datobibliograficoElement);
                        XElement editorialElement = new XElement("editorial");
                        datobibliograficoElement.Add(editorialElement);
                        if (tDoctrinaSumario.IdEditorial.HasValue)
                        {
                            editorialElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tEditorial, tDoctrinaSumario.IdEditorial.Value); //  Debe coincidir con la editorial cargada en SAE, en este caso el mapeo sera desde el id de la tabla tEditorial hacia una descripcion varchar que exista en Editoriales de SAE. tDoctrinaSumario.IdEditorial tObra.IdEditorial
                        }
                        // No informar
                        datobibliograficoElement.Add(new XElement("lugar"));
                        XElement fechaElement = new XElement("fecha");
                        //if (tDoctrinaSumario.FechaAlta.HasValue)
                        //{
                        //    fechaElement.Value = tDoctrinaSumario.FechaAlta.Value.ToStringSAE();
                        //}
                        datobibliograficoElement.Add(fechaElement); // No especifica de donde se obtiene el valor
                        // No informar
                        datobibliograficoElement.Add(new XElement("nro-edicion"));
                        datobibliograficoElement.Add(new XElement("nro-tomo"));

                        XElement fechapublicacionElement = new XElement("fecha-publicacion");
                        datobibliograficoElement.Add(fechapublicacionElement);
                        fechapublicacionElement.Value = tDoctrinaSumario.FechaPublicacion; // 22-08-11 Se agrego el valor
                        XElement cantpaginasElement = new XElement("cant-paginas");
                        datobibliograficoElement.Add(cantpaginasElement); // Se puede calcular?
                        XElement observacionesElement = new XElement("observaciones");
                        datobibliograficoElement.Add(observacionesElement); // No especifica de donde se obtiene el valor

                        // 21-08-11 Agrego la parte de Autores de Doctrina
                        // 22-08-11 Agrego valores
                        XElement autorpublicadoElement = new XElement("autor-publicado");
                        metaDocumentoElement.Add(autorpublicadoElement);
                        autorpublicadoElement.Add(new XAttribute("otros", "false"));
                        // 			Esto surge también del mapeo de Autores. Tenelo en cuenta en la tabla de conversión
                        foreach (var autor in tDoctrinaSumario.tDoctrinaSumarioAutor)
                        {
                            XElement autorElement = new XElement("autor");
                            autorpublicadoElement.Add(autorElement);
                            autorElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tAutor, autor.IdAutor);
                        }


                        // No informar
                        metaDocumentoElement.Add(new XElement("codigo-producto"));
                        metaDocumentoElement.Add(new XElement("comentarista"));

                        // Agrego la parte de publicacion de Doctrina
                        XElement publicacionElement = new XElement("publicacion");
                        metaDocumentoElement.Add(publicacionElement);
                        publicacionElement.Value = "Doctrina"; // No especifica de donde obtener ese valor, incorporo el valor del ejemplo

                        // No informar
                        metaDocumentoElement.Add(new XElement("asignaciones"));

                        // Agrego las Collection-sets
                        XElement collectionsSetElement = new XElement("collection-sets");
                        metaDocumentoElement.Add(collectionsSetElement);
                        // Se agregan los productos
                        foreach (tProducto tproducto in tDoctrinaSumario.tProducto1)
                        {
                            List<Guid> guidForProductoList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tProducto, tproducto.id_producto);

                            foreach (Guid guidForProducto in guidForProductoList)
                            {
                                XElement collectionSetElement = new XElement("collection-set");
                                collectionsSetElement.Add(collectionSetElement);
                                collectionSetElement.Value = guidForProducto.ToString();
                            }
                        }

                        // No informar
                        metaDocumentoElement.Add(new XElement("productos-digitales"));
                        metaDocumentoElement.Add(new XElement("legislacion-vinculada"));

                        // Agrego la Jurisprudencia vinculada
                        XElement jurisprudenciavinculadaElement = new XElement("jurisprudenciaVinculada");
                        metaDocumentoElement.Add(jurisprudenciavinculadaElement);
                        CargarDocumentosRelacionadosParaDoctrina(ctxPeOnline, jurisprudenciavinculadaElement, tDoctrinaSumario);


                        // Genero listado de voces filtradas por el arbol de voces
                        List<MigraVoz> vocesFiltradasPorArbolDeVoces = new List<MigraVoz>();

                        foreach (tDoctrinaSumario ds in doctrinaSumarioList)
                        {
                            List<MigraVoz> vocesFiltradasPorArbolDeVocesParaDoctrina = (from dst in ds.tDoctrinaSumarioTaxonomia
                                                                                        orderby dst.Nivel, dst.Nro
                                                                                        select new MigraVoz
                                                                                        {
                                                                                            Nombre = HtmlDecode(dst.tTaxonomia.Nombre),
                                                                                            IdTaxonomia = dst.IdTaxonomia,
                                                                                            Nivel = dst.Nivel.Value,
                                                                                            Numero = dst.Nro
                                                                                        }).ToList();

                            vocesFiltradasPorArbolDeVocesParaDoctrina = FiltrarPorArbolDeVoces(vocesFiltradasPorArbolDeVocesParaDoctrina);
                            // Agrego las voces que no están repetidas
                            foreach (var vozfiltrada in vocesFiltradasPorArbolDeVocesParaDoctrina)
                            {
                                if (vocesFiltradasPorArbolDeVoces.Where(v => v.IdTaxonomia == vozfiltrada.IdTaxonomia).Count() == 0)
                                {
                                    vocesFiltradasPorArbolDeVoces.Add(vozfiltrada);
                                }
                            }                            
                        }                                                                        

                        // Agrego Voces, Comento el codigo existente referente a las voces, porque no son las mismas
                        XElement vocesElement = new XElement("voces");
                        metaDocumentoElement.Add(vocesElement);
                        XElement nomencladorElement = new XElement("nomenclador");
                        vocesElement.Add(nomencladorElement);
                        XElement referenciaElement = new XElement("referencia");
                        vocesElement.Add(referenciaElement);
                        XElement unificadoElement = new XElement("unificado");
                        vocesElement.Add(unificadoElement);

                        // Procesamiento de voces
                        foreach (MigraVoz migraVoz in vocesFiltradasPorArbolDeVoces)
                        {
                            XElement vozElement = new XElement("voz");
                            vozElement.Add(new XAttribute("numero", migraVoz.Numero));
                            vozElement.Add(new XAttribute("nivel", migraVoz.Nivel));
                            vozElement.Add(new XAttribute("id_taxonomia", migraVoz.IdTaxonomia));
                            vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                            vozElement.Value = migraVoz.Nombre;
                            unificadoElement.Add(vozElement);
                        }

                        XElement contenidoDocumentoElement = new XElement("cont-documento");
                        documentoElement.Add(contenidoDocumentoElement);
                        XElement sumarioDoctrinaElement = new XElement("sumario-doctrina");
                        contenidoDocumentoElement.Add(sumarioDoctrinaElement); // No informar, no se puede separar del texto
                        StringBuilder builer = new StringBuilder();

                        builer.Append("<texto-doctrina>");
                        builer.Append(EscapearTexto(tDoctrinaSumario.tDoctrinaTexto.Cuerpo));
                        builer.Append("</texto-doctrina>");

                        builer.Append("<notas-texto>");
                        builer.Append(EscapearTexto(tDoctrinaSumario.tDoctrinaTexto.Notas));
                        builer.Append("</notas-texto>");

                        string documentText = ProcesarCuerpo(ctxPeOnline, doctrinaGuid, tDoctrinaSumario.IdDDSumario, builer.ToString(), false);

                        XElement textoDoctrinaElement = new XElement("texto-doctrina");
                        contenidoDocumentoElement.Add(textoDoctrinaElement);
                        textoDoctrinaElement.Add(new XCData(GetTextBetweenTags(documentText, "<texto-doctrina>", "</texto-doctrina>")));

                        XElement notasDoctrinaElement = new XElement("notas-texto");
                        contenidoDocumentoElement.Add(notasDoctrinaElement);
                        notasDoctrinaElement.Add(new XCData(GetTextBetweenTags(documentText, "<notas-texto>", "</notas-texto>")));

                        XElement abstractDoctrinaElement = new XElement("abstract");
                        contenidoDocumentoElement.Add(abstractDoctrinaElement);

                        string path = Path.Combine(this.OutputPath, "Doctrina");
                        if (!Directory.Exists(path))
                        {
                            Directory.CreateDirectory(path);
                        }

                        doctrinaDocument.Save(Path.Combine(path, nombreDocumento));

                        if (grupoDoctrina != null)
                        {
                            grupoDoctrina.Procesado = true;                         
                        }
                    }
                }
                catch (Exception ex)
                {
                    migraDocLogEntry.Excepcion = true;
                    string message = GetExceptionMessage(ex);
                    string stack = GetExceptionStackTrace(ex);
                    migraDocLogEntry.Mensaje = migraDocLogEntry.Mensaje + message + stack;
                    throw;
                }
                finally
                {
                    ctxPeOnline.MigraDocLog.AddObject(migraDocLogEntry);
                    ctxPeOnline.SaveChanges();
                }
            }
        }

        private void GenerarXMLObra(int idObra)
        {
            using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
            {
                List<tObraCuerpo> cuerposDeObra = ctxPeOnline.tObraCuerpo.Where(c => c.IdObra == idObra).ToList();

                tObra tObra = ctxPeOnline.tObra.Where(o => o.IdObra == idObra).SingleOrDefault();

                if (tObra == null)
                {
                    LogStatusMessage("No se encontró la obra", MigracionLogStatus.Information);
                    return;
                }

                if (!this.ProcesarSoloIdCuerpo)
                {
                    ProcesarIndice(ctxPeOnline, tObra);
                }

                if (!this.ProcesarSoloIndice)
                {
                    foreach (tObraCuerpo tObraCuerpo in cuerposDeObra)
                    {
                        if (this.ProcesarSoloIdCuerpo)
                        {
                            if (tObraCuerpo.IdCuerpo != this.IdCuerpoParam)//56752)
                                continue;
                        }
                        //if (tObraCuerpo.IdCuerpo != 59595)//56752)
                        //    continue;

                        string nombreDocumento = idObra.ToString() + "_" + tObraCuerpo.IdCuerpo + ".xml";
                        MigraDocLog migraDocLogEntry = new MigraDocLog();
                        migraDocLogEntry.NombreArchivoGenerado = nombreDocumento;
                        migraDocLogEntry.ApNombreTabla = IdentityTranslationManager.tObraCuerpo;
                        migraDocLogEntry.Excepcion = false;
                        migraDocLogEntry.Mensaje = string.Empty;

                        try
                        {
                            XDocument obraDocument = new XDocument();

                            XElement documentoElement = new XElement("documento");
                            obraDocument.Add(documentoElement);

                            XElement metaDocumentoElement = new XElement("meta-documento");
                            documentoElement.Add(metaDocumentoElement);

                            XElement tipoDoctrinaElement = new XElement("tipo-doctrina");
                            metaDocumentoElement.Add(tipoDoctrinaElement);
                            tipoDoctrinaElement.Value = "Libro Online";
                            XElement subtipoDoctrinaElement = new XElement("subtipo-doctrina");
                            metaDocumentoElement.Add(subtipoDoctrinaElement);
                            subtipoDoctrinaElement.Value = "Tratados o Grandes Obras";

                            XElement obraElement = new XElement("guid-obra");
                            metaDocumentoElement.Add(obraElement);
                            Guid obraGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tObra, tObra.IdObra);
                            obraElement.Value = obraGuid.ToString();

                            XElement doctrinaGuidElement = new XElement("guid");
                            metaDocumentoElement.Add(doctrinaGuidElement);
                            Guid doctrinaGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tObraCuerpo, tObraCuerpo.IdCuerpo);
                            doctrinaGuidElement.Value = doctrinaGuid.ToString();
                            migraDocLogEntry.GuidSae = doctrinaGuid;
                            migraDocLogEntry.ApId = tObraCuerpo.IdCuerpo.ToString();

                            metaDocumentoElement.Add(new XElement("iddoc")); // No informar
                            XElement citaElement = new XElement("cita");
                            metaDocumentoElement.Add(citaElement);
                            int idIdentLexis = Convert.ToInt32(tObraCuerpo.IdIdentLexis);
                            tIdentLexis tIdentLexis = ctxPeOnline.tIdentLexis.Where(i => i.Id == idIdentLexis).Single();
                            citaElement.Value = tIdentLexis.IdentLexis;
                            XElement novusElement = new XElement("novus", new XElement("id"), new XElement("accion", IdTranslationManager.GetDocumentoEstadoEnviarNovus(3)), new XElement("fecha-de-modificacion", "T"));
                            metaDocumentoElement.Add(novusElement);
                            XElement fechaDeCarga = new XElement("fecha-carga");
                            metaDocumentoElement.Add(fechaDeCarga);
                            fechaDeCarga.Value = tObra.FechaAlta.ToStringSAE();
                            metaDocumentoElement.Add(new XElement("fecha-ultima-modificacion", DateTime.Now.ToStringSAE()));
                            metaDocumentoElement.Add(new XElement("estado-texto", StrEstadoConTexto));
                            metaDocumentoElement.Add(new XElement("notas-internas", StrNotaInterna));
                            XElement tituloElement = new XElement("titulo-publicado");
                            metaDocumentoElement.Add(tituloElement);
                            tituloElement.Value = HtmlDecode(tObra.Titulo);
                            // Materias
                            XElement materiasElement = new XElement("materias");
                            metaDocumentoElement.Add(materiasElement);

                            List<int> materiasDeObraIdList = ctxPeOnline.tObraMateria.Where(om => om.IdObra == tObra.IdObra && om.Id_Materia.HasValue).Select(om => om.Id_Materia.Value).ToList();
                            List<tMateria> materiasDeObraList = ctxPeOnline.tMateria.Where(om => materiasDeObraIdList.Contains(om.id_Materia)).ToList();
                            foreach (var tobraMateria in materiasDeObraList)
                            {
                                tMateria materia = ctxPeOnline.tMateria.Where(m => m.id_Materia == tobraMateria.id_Materia).Single();
                                List<Guid> guidSaeMateriaList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tMateria, materia.id_Materia);//GetGuidListIdForApEntity
                                foreach (Guid guidSaeMateria in guidSaeMateriaList)
                                {
                                    XElement materiaElement = new XElement("materia");
                                    materiaElement.Add(new XAttribute("identificador", materia.Identificador));
                                    materiaElement.Add(new XAttribute("nombre", HtmlDecode(materia.Descripcion)));
                                    materiaElement.Value = guidSaeMateria.ToString();
                                    materiasElement.Add(materiaElement);
                                }
                            }

                            XElement aparicionesElement = new XElement("apariciones");
                            metaDocumentoElement.Add(aparicionesElement);
                            metaDocumentoElement.Add(new XElement("pais", StrPais));
                            metaDocumentoElement.Add(new XElement("aparicionesfuturas"));
                            metaDocumentoElement.Add(new XElement("boletin"));
                            XElement datobibliograficoElement = new XElement("dato-bibliografico");
                            metaDocumentoElement.Add(datobibliograficoElement);
                            XElement editorialElement = new XElement("editorial");
                            datobibliograficoElement.Add(editorialElement);
                            if (tObra.IdEditorial.HasValue)
                            {
                                editorialElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tEditorial, tObra.IdEditorial.Value);
                            }
                            // No informar
                            datobibliograficoElement.Add(new XElement("lugar"));

                            XElement fechaElement = new XElement("fecha");
                            //if (tObra.FechaAlta.HasValue)
                            //{
                            //    fechaElement.Value = tObra.FechaAlta.Value.ToStringSAE();
                            //}
                            datobibliograficoElement.Add(fechaElement); // No especifica de donde se obtiene el valor
                            datobibliograficoElement.Add(new XElement("nro-edicion", tObra.Edicion));
                            datobibliograficoElement.Add(new XElement("nro-tomo", tObra.Tomo));
                            XElement fechapublicacionElement = new XElement("fecha-publicacion");
                            datobibliograficoElement.Add(fechapublicacionElement);
                            fechapublicacionElement.Value = tObra.Anio;
                            XElement cantpaginasElement = new XElement("cant-paginas");
                            datobibliograficoElement.Add(cantpaginasElement); // Se puede calcular?
                            XElement observacionesElement = new XElement("observaciones");
                            datobibliograficoElement.Add(observacionesElement); // No especifica de donde se obtiene el valor
                            XElement autorpublicadoElement = new XElement("autor-publicado");
                            metaDocumentoElement.Add(autorpublicadoElement);
                            autorpublicadoElement.Add(new XAttribute("otros", "false"));
                            foreach (var autor in tObra.tObraAutor)
                            {
                                XElement autorElement = new XElement("autor");
                                autorpublicadoElement.Add(autorElement);
                                autorElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tAutor, autor.IdAutor);
                            }

                            // No informar
                            metaDocumentoElement.Add(new XElement("codigo-producto"));
                            metaDocumentoElement.Add(new XElement("comentarista"));

                            XElement publicacionElement = new XElement("publicacion");
                            metaDocumentoElement.Add(publicacionElement);
                            publicacionElement.Value = "Doctrina"; // No especifica de donde obtener ese valor, incorporo el valor del ejemplo

                            // No informar
                            metaDocumentoElement.Add(new XElement("asignaciones"));

                            XElement collectionsSetElement = new XElement("collection-sets");
                            metaDocumentoElement.Add(collectionsSetElement);
                            foreach (tProducto tproducto in tObra.tProducto1)
                            {
                                List<Guid> guidForProductoList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tProducto, tproducto.id_producto);

                                foreach (Guid guidForProducto in guidForProductoList)
                                {
                                    XElement collectionSetElement = new XElement("collection-set");
                                    collectionsSetElement.Add(collectionSetElement);
                                    collectionSetElement.Value = guidForProducto.ToString();
                                }
                            }

                            // No informar
                            metaDocumentoElement.Add(new XElement("productos-digitales"));
                            metaDocumentoElement.Add(new XElement("legislacion-vinculada"));
                            metaDocumentoElement.Add(new XElement("jurisprudenciaVinculada"));

                            // Genero listado de voces filtradas por el arbol de voces
                            List<MigraVoz> vocesFiltradasPorArbolDeVoces = (from ot in ctxPeOnline.tObraTaxonomia
                                                                            join ta in ctxPeOnline.tTaxonomia on ot.IdTaxonomia equals ta.IdTaxonomia
                                                                            where ot.IdCuerpo == tObraCuerpo.IdCuerpo
                                                                            orderby ot.Nivel, ot.Nro
                                                                            select new MigraVoz
                                                                            {
                                                                                Nombre = ot.tTaxonomia.Nombre,
                                                                                IdTaxonomia = ot.IdTaxonomia,
                                                                                Nivel = ot.Nivel,
                                                                                Numero = ot.Nro ?? 0
                                                                            }).ToList();

                            if (vocesFiltradasPorArbolDeVoces.Count == 0)
                            {
                                if (tObraCuerpo.Voz.HasValue)
                                {
                                    //tObraCuerpo.Voz
                                    int idVoz = tObraCuerpo.Voz.Value;
                                    int nivelInverso = 0;
                                    using (ArbolDeVocesEntities ctxArbolDeVoces = new ArbolDeVocesEntities())
                                    {
                                        tVoce tVoz = ctxArbolDeVoces.tVoces.Where(v => v.IdVoz == idVoz).SingleOrDefault();
                                        while (tVoz != null)
                                        {
                                            vocesFiltradasPorArbolDeVoces.Add(new MigraVoz
                                                                            {
                                                                                Nombre = tVoz.Descripcion,
                                                                                IdTaxonomia = 0,
                                                                                Nivel = nivelInverso,
                                                                                Numero = nivelInverso
                                                                            });

                                            idVoz = ctxArbolDeVoces.tJerarquias.Where(j => j.IdVozH == idVoz).Select(v => v.IdVozP).SingleOrDefault();
                                            nivelInverso++;
                                            tVoz = ctxArbolDeVoces.tVoces.Where(v => v.IdVoz == idVoz).SingleOrDefault();
                                        }

                                        if (vocesFiltradasPorArbolDeVoces.Count > 0)
                                        {
                                            int max = vocesFiltradasPorArbolDeVoces.Count;
                                            vocesFiltradasPorArbolDeVoces.ForEach(v => { v.Nivel = max - v.Nivel; v.Numero = max - v.Numero; });
                                            vocesFiltradasPorArbolDeVoces = (from v in vocesFiltradasPorArbolDeVoces
                                                                             orderby v.Nivel
                                                                             select v).ToList();
                                        }
                                    }
                                }
                            }

                            vocesFiltradasPorArbolDeVoces.ForEach(v => v.Nombre = HtmlDecode(v.Nombre));

                            vocesFiltradasPorArbolDeVoces = FiltrarPorArbolDeVoces(vocesFiltradasPorArbolDeVoces);

                            // Agrego Voces, Comento el codigo existente referente a las voces, porque no son las mismas
                            XElement vocesElement = new XElement("voces");
                            metaDocumentoElement.Add(vocesElement);
                            XElement nomencladorElement = new XElement("nomenclador");
                            vocesElement.Add(nomencladorElement);
                            XElement referenciaElement = new XElement("referencia");
                            vocesElement.Add(referenciaElement);
                            XElement unificadoElement = new XElement("unificado");
                            vocesElement.Add(unificadoElement);

                            // Procesamiento de voces
                            foreach (MigraVoz migraVoz in vocesFiltradasPorArbolDeVoces)
                            {
                                XElement vozElement = new XElement("voz");
                                vozElement.Add(new XAttribute("numero", migraVoz.Numero));
                                vozElement.Add(new XAttribute("nivel", migraVoz.Nivel));
                                vozElement.Add(new XAttribute("id_taxonomia", migraVoz.IdTaxonomia));
                                vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                                vozElement.Value = migraVoz.Nombre;
                                unificadoElement.Add(vozElement);
                            }

                            XElement contenidoDocumentoElement = new XElement("cont-documento");
                            documentoElement.Add(contenidoDocumentoElement);

                            contenidoDocumentoElement.Add(new XElement("nro-cuerpo", (tObraCuerpo.NumCuerpo * 10).ToString()));

                            contenidoDocumentoElement.Add(new XElement("sumario-doctrina")); // No informar

                            StringBuilder builer = new StringBuilder();


                            builer.Append("<texto-doctrina>");
                            builer.Append(EscapearTexto(tObraCuerpo.tObraTexto.Texto));
                            builer.Append("</texto-doctrina>");

                            builer.Append("<notas-texto>");
                            builer.Append(EscapearTexto(tObraCuerpo.tObraTexto.Notas));
                            builer.Append("</notas-texto>");

                            builer.Append("<abstract>");
                            builer.Append(EscapearTexto(tObra.Resumen));
                            builer.Append("</abstract>");

                            string documentText = ProcesarCuerpo(ctxPeOnline, doctrinaGuid, tObraCuerpo.IdCuerpo, builer.ToString(), false);

                            XElement textoDoctrinaElement = new XElement("texto-doctrina");
                            contenidoDocumentoElement.Add(textoDoctrinaElement);
                            textoDoctrinaElement.Add(new XCData(GetTextBetweenTags(documentText, "<texto-doctrina>", "</texto-doctrina>")));

                            XElement notasDoctrinaElement = new XElement("notas-texto");
                            contenidoDocumentoElement.Add(notasDoctrinaElement);
                            notasDoctrinaElement.Add(new XCData(GetTextBetweenTags(documentText, "<notas-texto>", "</notas-texto>")));

                            XElement abstractDoctrinaElement = new XElement("abstract");
                            contenidoDocumentoElement.Add(abstractDoctrinaElement);
                            abstractDoctrinaElement.Add(new XCData(GetTextBetweenTags(documentText, "<abstract>", "</abstract>")));

                            //contenidoDocumentoElement.Add(new XCData(documentText));

                            //XElement textoDoctrinaElement = new XElement("texto-doctrina");
                            //contenidoDocumentoElement.Add(textoDoctrinaElement);
                            //textoDoctrinaElement.Add(new XCData(ProcesarCuerpo(ctxPeOnline, doctrinaGuid, tObraCuerpo.IdCuerpo, tObraCuerpo.tObraTexto.Texto)));

                            //XElement notasTextoElement = new XElement("notas-texto");
                            //textoDoctrinaElement.Add(notasTextoElement);
                            //if (tObraCuerpo.tObraTexto.Notas != null)
                            //{
                            //   notasTextoElement.Add(new XCData(ProcesarCuerpo(ctxPeOnline, doctrinaGuid, tObraCuerpo.IdCuerpo, tObraCuerpo.tObraTexto.Notas)));                           
                            //}

                            //XElement abstractElement = new XElement("abstract");
                            //contenidoDocumentoElement.Add(abstractElement);
                            //if (tObra.Resumen != null)
                            //{
                            //    notasTextoElement.Add(new XCData(ProcesarCuerpo(ctxPeOnline, doctrinaGuid, tObraCuerpo.IdCuerpo, tObra.Resumen)));                            
                            //}

                            string path = Path.Combine(this.OutputPath, "Obra");
                            if (!Directory.Exists(path))
                            {
                                Directory.CreateDirectory(path);
                            }
                            obraDocument.Save(Path.Combine(path, nombreDocumento));
                        }
                        catch (Exception ex)
                        {
                            migraDocLogEntry.Excepcion = true;
                            string message = GetExceptionMessage(ex);
                            string stack = GetExceptionStackTrace(ex);
                            migraDocLogEntry.Mensaje = migraDocLogEntry.Mensaje + message + stack;
                            LogStatusMessage(migraDocLogEntry.Mensaje, MigracionLogStatus.Error);
                        }
                        finally
                        {
                            ctxPeOnline.MigraDocLog.AddObject(migraDocLogEntry);
                            ctxPeOnline.SaveChanges();
                        }
                    }
                }
            }
        }

        private void ProcesarIndice(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, tObra tObra)
        {
            string nombreDocumento = tObra.IdObra.ToString() + ".xml";
            MigraDocLog migraDocLogEntry = new MigraDocLog();
            migraDocLogEntry.NombreArchivoGenerado = nombreDocumento;
            migraDocLogEntry.ApNombreTabla = IdentityTranslationManager.tObraCuerpo;
            migraDocLogEntry.Excepcion = false;
            migraDocLogEntry.Mensaje = string.Empty;

            try
            {
                XDocument obraDocument = new XDocument();

                XElement documentoElement = new XElement("documento");
                obraDocument.Add(documentoElement);

                XElement metaDocumentoElement = new XElement("meta-documento");
                documentoElement.Add(metaDocumentoElement);

                XElement tipoDoctrinaElement = new XElement("tipo-doctrina");
                metaDocumentoElement.Add(tipoDoctrinaElement);
                tipoDoctrinaElement.Value = "Indice";
                XElement subtipoDoctrinaElement = new XElement("subtipo-doctrina");
                metaDocumentoElement.Add(subtipoDoctrinaElement);
                //subtipoDoctrinaElement.Value = "Tratados o Grandes Obras";

                XElement obraElement = new XElement("guid-obra");
                metaDocumentoElement.Add(obraElement);
                Guid obraGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tObra, tObra.IdObra);
                obraElement.Value = obraGuid.ToString();

                XElement doctrinaGuidElement = new XElement("guid");
                metaDocumentoElement.Add(doctrinaGuidElement);
                
                Guid doctrinaGuid = obraGuid;
                doctrinaGuidElement.Value = doctrinaGuid.ToString();
                migraDocLogEntry.GuidSae = doctrinaGuid;
                migraDocLogEntry.ApId = tObra.IdObra.ToString();

                metaDocumentoElement.Add(new XElement("iddoc")); // No informar
                XElement citaElement = new XElement("cita");
                metaDocumentoElement.Add(citaElement);
                //int idIdentLexis = Convert.ToInt32(tObraCuerpo.IdIdentLexis);
                //tIdentLexis tIdentLexis = ctxPeOnline.tIdentLexis.Where(i => i.Id == idIdentLexis).Single();
                //citaElement.Value = tIdentLexis.IdentLexis;

                XElement novusElement = new XElement("novus", new XElement("id"), new XElement("accion", IdTranslationManager.GetDocumentoEstadoEnviarNovus(3)), new XElement("fecha-de-modificacion", "T"));
                metaDocumentoElement.Add(novusElement);
                XElement fechaDeCarga = new XElement("fecha-carga");
                metaDocumentoElement.Add(fechaDeCarga);
                fechaDeCarga.Value = tObra.FechaAlta.ToStringSAE();
                metaDocumentoElement.Add(new XElement("fecha-ultima-modificacion", DateTime.Now.ToStringSAE()));
                metaDocumentoElement.Add(new XElement("estado-texto", StrEstadoConTexto));
                metaDocumentoElement.Add(new XElement("notas-internas", StrNotaInterna));
                XElement tituloElement = new XElement("titulo-publicado");
                metaDocumentoElement.Add(tituloElement);
                tituloElement.Value = HtmlDecode(tObra.Titulo);
                // Materias
                XElement materiasElement = new XElement("materias");
                metaDocumentoElement.Add(materiasElement);

                List<int> materiasDeObraIdList = ctxPeOnline.tObraMateria.Where(om => om.IdObra == tObra.IdObra && om.Id_Materia.HasValue).Select(om => om.Id_Materia.Value).ToList();
                List<tMateria> materiasDeObraList = ctxPeOnline.tMateria.Where(om => materiasDeObraIdList.Contains(om.id_Materia)).ToList();
                foreach (var tobraMateria in materiasDeObraList)
                {
                    tMateria materia = ctxPeOnline.tMateria.Where(m => m.id_Materia == tobraMateria.id_Materia).Single();
                    List<Guid> guidSaeMateriaList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tMateria, materia.id_Materia);//GetGuidListIdForApEntity
                    foreach (Guid guidSaeMateria in guidSaeMateriaList)
                    {
                        XElement materiaElement = new XElement("materia");
                        materiaElement.Add(new XAttribute("identificador", materia.Identificador));
                        materiaElement.Add(new XAttribute("nombre", HtmlDecode(materia.Descripcion)));
                        materiaElement.Value = guidSaeMateria.ToString();
                        materiasElement.Add(materiaElement);
                    }
                }

                XElement aparicionesElement = new XElement("apariciones");
                metaDocumentoElement.Add(aparicionesElement);
                metaDocumentoElement.Add(new XElement("pais", StrPais));
                metaDocumentoElement.Add(new XElement("aparicionesfuturas"));
                metaDocumentoElement.Add(new XElement("boletin"));
                XElement datobibliograficoElement = new XElement("dato-bibliografico");
                metaDocumentoElement.Add(datobibliograficoElement);
                XElement editorialElement = new XElement("editorial");
                datobibliograficoElement.Add(editorialElement);
                if (tObra.IdEditorial.HasValue)
                {
                    editorialElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tEditorial, tObra.IdEditorial.Value);
                }
                // No informar
                datobibliograficoElement.Add(new XElement("lugar"));

                XElement fechaElement = new XElement("fecha");
                if (tObra.FechaAlta.HasValue)
                {
                    fechaElement.Value = tObra.FechaAlta.Value.ToStringSAE();
                }
                datobibliograficoElement.Add(fechaElement); // No especifica de donde se obtiene el valor
                datobibliograficoElement.Add(new XElement("nro-edicion", tObra.Edicion));
                datobibliograficoElement.Add(new XElement("nro-tomo", tObra.Tomo));
                XElement fechapublicacionElement = new XElement("fecha-publicacion");
                datobibliograficoElement.Add(fechapublicacionElement);
                fechapublicacionElement.Value = tObra.Anio;
                XElement cantpaginasElement = new XElement("cant-paginas");
                datobibliograficoElement.Add(cantpaginasElement); // Se puede calcular?
                XElement observacionesElement = new XElement("observaciones");
                datobibliograficoElement.Add(observacionesElement); // No especifica de donde se obtiene el valor
                XElement autorpublicadoElement = new XElement("autor-publicado");
                metaDocumentoElement.Add(autorpublicadoElement);
                autorpublicadoElement.Add(new XAttribute("otros", "false"));
                foreach (var autor in tObra.tObraAutor)
                {
                    XElement autorElement = new XElement("autor");
                    autorpublicadoElement.Add(autorElement);
                    autorElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tAutor, autor.IdAutor);
                }

                // No informar
                metaDocumentoElement.Add(new XElement("codigo-producto"));
                metaDocumentoElement.Add(new XElement("comentarista"));

                XElement publicacionElement = new XElement("publicacion");
                metaDocumentoElement.Add(publicacionElement);
                publicacionElement.Value = "Doctrina"; // No especifica de donde obtener ese valor, incorporo el valor del ejemplo

                // No informar
                metaDocumentoElement.Add(new XElement("asignaciones"));

                XElement collectionsSetElement = new XElement("collection-sets");
                metaDocumentoElement.Add(collectionsSetElement);
                foreach (tProducto tproducto in tObra.tProducto1)
                {
                    List<Guid> guidForProductoList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tProducto, tproducto.id_producto);

                    foreach (Guid guidForProducto in guidForProductoList)
                    {
                        XElement collectionSetElement = new XElement("collection-set");
                        collectionsSetElement.Add(collectionSetElement);
                        collectionSetElement.Value = guidForProducto.ToString();
                    }
                }

                // No informar
                metaDocumentoElement.Add(new XElement("productos-digitales"));
                metaDocumentoElement.Add(new XElement("legislacion-vinculada"));
                metaDocumentoElement.Add(new XElement("jurisprudenciaVinculada"));

                //// Genero listado de voces filtradas por el arbol de voces
                //List<MigraVoz> vocesFiltradasPorArbolDeVoces = (from ot in ctxPeOnline.tObraTaxonomia
                //                                                join ta in ctxPeOnline.tTaxonomia on ot.IdTaxonomia equals ta.IdTaxonomia
                //                                                where ot.IdCuerpo == tObraCuerpo.IdCuerpo
                //                                                orderby ot.Nivel, ot.Nro
                //                                                select new MigraVoz
                //                                                {
                //                                                    Nombre = ot.tTaxonomia.Nombre,
                //                                                    IdTaxonomia = ot.IdTaxonomia,
                //                                                    Nivel = ot.Nivel,
                //                                                    Numero = ot.Nro.Value
                //                                                }).ToList();

                //vocesFiltradasPorArbolDeVoces.ForEach(v => v.Nombre = HtmlDecode(v.Nombre));

                //vocesFiltradasPorArbolDeVoces = FiltrarPorArbolDeVoces(vocesFiltradasPorArbolDeVoces);

                // Agrego Voces, Comento el codigo existente referente a las voces, porque no son las mismas
                XElement vocesElement = new XElement("voces");
                metaDocumentoElement.Add(vocesElement);
                XElement nomencladorElement = new XElement("nomenclador");
                vocesElement.Add(nomencladorElement);
                XElement referenciaElement = new XElement("referencia");
                vocesElement.Add(referenciaElement);
                XElement unificadoElement = new XElement("unificado");
                vocesElement.Add(unificadoElement);

                //// Procesamiento de voces
                //foreach (MigraVoz migraVoz in vocesFiltradasPorArbolDeVoces)
                //{
                //    XElement vozElement = new XElement("voz");
                //    vozElement.Add(new XAttribute("numero", migraVoz.Numero));
                //    vozElement.Add(new XAttribute("nivel", migraVoz.Nivel));
                //    vozElement.Add(new XAttribute("id_taxonomia", migraVoz.IdTaxonomia));
                //    vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                //    vozElement.Value = migraVoz.Nombre;
                //    unificadoElement.Add(vozElement);
                //}

                XElement contenidoDocumentoElement = new XElement("cont-documento");
                documentoElement.Add(contenidoDocumentoElement);

                contenidoDocumentoElement.Add(new XElement("nro-cuerpo")); //, (tObraCuerpo.NumCuerpo * 10).ToString()));

                contenidoDocumentoElement.Add(new XElement("sumario-doctrina")); // No informar

                XElement textoDoctrinaElement = new XElement("texto-doctrina");
                contenidoDocumentoElement.Add(textoDoctrinaElement);
                textoDoctrinaElement.Add(new XCData(ProcesarCuerpo(ctxPeOnline, doctrinaGuid, tObra.IdObra, tObra.Indice, usarVerTexto: false)));

                string path = Path.Combine(this.OutputPath, "Obra");
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                obraDocument.Save(Path.Combine(path, nombreDocumento));
            }
            catch (Exception ex)
            {
                migraDocLogEntry.Excepcion = true;
                string message = GetExceptionMessage(ex);
                string stack = GetExceptionStackTrace(ex);
                migraDocLogEntry.Mensaje = migraDocLogEntry.Mensaje + message + stack;
                LogStatusMessage(message + stack, MigracionLogStatus.Error);
            }
            finally
            {
                ctxPeOnline.MigraDocLog.AddObject(migraDocLogEntry);
                ctxPeOnline.SaveChanges();
            }
        }
         
        private void CargarDocumentosRelacionadosParaDoctrina(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, XElement documentosRelacionadosElement, tDoctrinaSumario doctrinaSumario)
        {
            if (!String.IsNullOrEmpty(doctrinaSumario.tDoctrinaTexto.Comentario))
            {
                string comentario = HtmlDecode(doctrinaSumario.tDoctrinaTexto.Comentario);                
                comentario = "<root>" + comentario + "</root>";
                comentario = EscapearTexto(comentario);
                List<XElement> parrafosEnElComentario;
                using (StringReader strReader = new StringReader(comentario))
                {
                    XDocument xComentarioFallo = XDocument.Load(strReader);
                    parrafosEnElComentario = (from node in xComentarioFallo.Descendants()
                                              where node.Name == "Parrafo"
                                              select node).ToList();


                    foreach (var parrafoElement in parrafosEnElComentario)
                    {
                        if (!parrafoElement.Value.StartsWith("Comentario") && !String.IsNullOrEmpty(parrafoElement.Value))
                        {
                            string textoNota = HtmlDecode(parrafoElement.Value);

                            var citaElement = (from node in parrafoElement.Descendants()
                                               where node.Name == "Cita"
                                               && node.Attribute("tipo").Value == "jj_anotada"
                                               select node).SingleOrDefault();

                            if (citaElement == null)
                            {
                                citaElement = (from node in parrafoElement.Descendants()
                                               where node.Name == "Cita"
                                               && node.Attribute("tipo").Value == "lexis"
                                               select node).SingleOrDefault();
                            }

                            if (citaElement != null)
                            {
                                // Obtengo el documento de jurisprudencia
                                string archivofisico = citaElement.Attribute("ref").Value;
                                var jurisprudenciavinculada = ctxPeOnline.tJurisFallo.Where(jf => jf.ArchFisico == archivofisico && jf.IdIdentLexis.HasValue).SingleOrDefault();
                                if (jurisprudenciavinculada != null)
                                {
                                    XElement documentoElement = new XElement("documento");
                                    XElement guidRelacionadoElement = new XElement("guid");
                                    guidRelacionadoElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tDoctrinaSumario, jurisprudenciavinculada.IdJJ).ToString();
                                    documentoElement.Add(guidRelacionadoElement);
                                    documentoElement.Add(new XElement("subtipo", new XAttribute("sigla", "NF")));
                                    documentoElement.Add(new XElement("texto-ref", textoNota));
                                    documentosRelacionadosElement.Add(documentoElement);
                                }
                            }
                        }
                    }
                }
            }
        }             
    }
}
